/**
 
 * 
 */
package nl.boektrust.btsoep.server;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import nl.boektrust.btsoep.shared.Settings;
import nl.boektrust.btsoep.shared.model.BinaryAsset;
import nl.boektrust.btsoep.shared.model.ImageReferenceTypeCode;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.FinalizationException;
import com.google.appengine.api.files.LockException;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;

/**
 * @author rao3
 *
 * the implementation of the server that can serve XML requests to Koppelvlak bookstores. 
 */
public class ImportImageFileTask extends HttpServlet {
	private boolean isObjectifyServiceRegistered = false;
	private ServletContext context;
	String logMessage = new String("");
	int newBooks = 0;
	int updatedBooks = 0;
	int skippedBooks = 0;
	int deletedBooks = 0;
	PersistentServiceImpl persistentServiceImpl = new PersistentServiceImpl();

	
	ServletContext getContext() {
		return this.context;
	}

	public void init() throws ServletException {
		context = getServletContext();
		logMessage = new String("");
		persistentServiceImpl.registerServices();
		//System.err.println("Real Path = " + context.getRealPath("/"));
	}

	/**
	 * 
	 */
	public ImportImageFileTask() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param delegate
	 */
	public ImportImageFileTask(Object delegate) {
		//super(delegate);
		// TODO Auto-generated constructor stub
	}
	
	
	
	public void sendResponse(javax.servlet.http.HttpServletResponse response, String responseString) {
		response.setStatus(200);
		
		
		try {
			/*
			 * send with XMPP using the sendmessage servlet on the frontend
			 * 26 oct 2011: disable because this flooded the XMPP clients
			 */
			boolean sendMessage = false;
			if (sendMessage == true) {
				URL messagingurl = new URL(Settings.getBaseUrl()+"sendmessage?message="+URLEncoder.encode(responseString, "ascii"));
				BufferedReader reader = new BufferedReader(new InputStreamReader(messagingurl.openStream()));
				reader.close();
			}

			/*
			 * send same response to the browser
			 */
			response.getOutputStream().print("ImportCBOnixTask: "+ responseString+"\n");
			response.getOutputStream().close();

		} catch (IOException e) {
			System.err.println("ImportCBONixTask: IO exception thrown while sending HTTP response");
			System.err.println(stack2string(e));

		} catch (Exception e) {
			System.err.println("ImportCBONixTask: General exception thrown while sending HTTP response");
		}
	}
	
	public void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws ServletException, IOException  
	{
		
		/*
		 * get URl from the parameter list. 
		 */
		String urlString = request.getParameter("urlString");
		String recordReference = request.getParameter("recordReference");
		String imageType = request.getParameter("imageType");
		
		if (urlString == null || urlString.length() == 0) {
			System.err.println("ImportImageFileTask was called with no valid urlString");
			sendResponse(response, "url was not specified");
			return;
		}
		
		if (recordReference == null || recordReference.length() == 0) {
			System.err.println("ImportImageFileTask was called with no valid recordReference");
			sendResponse(response, "recordReference was not specified.");
			return;
		}
		if (imageType == null || imageType.length() == 0) {
			System.err.println("ImportImageFileTask was called with no valid imageType");
			sendResponse(response, "imageType was not specified");
			return;
		}
		String resultString = "";
		ImageReferenceTypeCode imageTypeCode = ImageReferenceTypeCode.UNDEFINED;
		if (imageType.toLowerCase().equals("frontcover")) imageTypeCode = ImageReferenceTypeCode.FRONTCOVER;
		else if (imageType.toLowerCase().equals("backcover")) imageTypeCode = ImageReferenceTypeCode.BACKCOVER;

		if (imageTypeCode != ImageReferenceTypeCode.UNDEFINED) {
			try {
				byte[] buffer = downloadFile(urlString);
				/*
				 * if the buffer is smaller than 1024, assume it was some sort of an error and bail out
				 */
				if (buffer.length < 1024) {
					String st = new String(buffer);
					System.err.println("ImportImageFileTask downloaded small file, assuming error, buffer contents: "+st);
					response.sendError(503);
					return;
				}
				/*
				 * if a blob already exists with these parameters, remove it first, to prevent duplicates
				 */
				long recref = Long.parseLong(recordReference);
				// System.err.println("Checking for previous assets");
				List<BinaryAsset> existingAssets = persistentServiceImpl.getBinaryAssets(recref, imageTypeCode);
				// System.err.println("Found "+existingAssets.size()+" assets");

				if (existingAssets.size() > 0) { 
					// System.err.println("Asset already exists, don't do anything");
					// persistentServiceImpl.deleteBinaryAssets(recref, imageTypeCode);	
					sendResponse(response, "ImportImageFileTask: asset exists, no action taken");
					return;
				} else {
					String filename = imageType+"."+recordReference+"."+"jpeg";
					BlobKey blobKey = storeImageAsBlob(buffer, filename);
					// System.err.println("blob key is: "+blobKey.toString());
					BinaryAsset b = new BinaryAsset();
					b.setOriginalUrl(urlString);
					b.setBlobKey(blobKey);
					b.setImageReferenceTypeCode(imageTypeCode);
					b.setRecordReference(recref);
					persistentServiceImpl.persistBinaryAsset(b);
					ImagesService imagesService = (ImagesService) ImagesServiceFactory.getImagesService();
					resultString = imagesService.getServingUrl(blobKey);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			System.err.println("ImportImageFileTask was called with an undefined imageReferenceTypeCode ");
			sendResponse(response, "ImportImageFileTask was called with an undefined imageReferenceTypeCode ");
			return;
		
		}

		sendResponse(response, "ImportImageFileTask finished importing URL "+urlString +" now at URL "+resultString);
	}

	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {

		
	}
	
	public BlobKey storeImageAsBlob(byte[] theImage, String filename) {
		// Get a file service
		FileService fileService = FileServiceFactory.getFileService();

		// Create a new Blob file with mime-type "text/plain"
		AppEngineFile file;
		BlobKey blobKey = null;
		try {
			file = fileService.createNewBlobFile("image/jpeg", filename);
			

			// This time lock because we intend to finalize
			boolean lock = true;
			FileWriteChannel writeChannel;
			writeChannel = fileService.openWriteChannel(file, lock);
			// This time we write to the channel using standard Java
			writeChannel.write( ByteBuffer.wrap(theImage));
			// Now finalize
			writeChannel.closeFinally();
			blobKey = fileService.getBlobKey(file);
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FinalizationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (LockException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return blobKey;
	}

	
	public byte[] downloadFile(String urlString) throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		URL url = new URL(urlString);
		BufferedInputStream in = new BufferedInputStream(url.openStream());

		byte[] buffer = new byte[8 * 1024];
		int count;
		while ((count = in.read(buffer)) >= 0) {
			output.write(buffer, 0, count);
		}
		in.close();
		return output.toByteArray();
	}

	

		
		
		public static String stack2string(Exception e) {
			try {
				StringWriter sw = new StringWriter();
				PrintWriter pw = new PrintWriter(sw);
				e.printStackTrace(pw);
				return "------\r\n" + sw.toString() + "------\r\n";
			}
			catch(Exception e2) {
				return "bad stack2string";
			}
		}
		



}
